package com.tentcoo.core.command;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.tentcoo.util.AssertUtils;
import com.tentcoo.util.ReflectionUtils;

/**
 * 命令管理器。
 * 
 * @author Allenz
 * @since 0.0.1-SNAPSHOT
 * 
 */
public class CommandManager {

	private static final Logger LOGGER = LoggerFactory
			.getLogger(CommandManager.class);

	private static Map<Class<? extends Command<?>>, CommandHandler<? extends Command<?>, ?>> handlerMap = new HashMap<Class<? extends Command<?>>, CommandHandler<? extends Command<?>, ?>>();

	/**
	 * 注册命令到命令处理器。
	 * 
	 * @param commandHandler
	 *            命令处理器
	 */
	public synchronized static void register(
			CommandHandler<? extends Command<?>, ?> commandHandler) {
		AssertUtils.notNull(commandHandler);

		Class<? extends Command<?>> commandClass = commandHandler
				.getCommandClass();
		if (handlerMap.containsKey(commandClass)) {
			LOGGER.warn("命令 '" + commandClass + "' 已经被注册，不再绑定命令处理器");
		} else {
			handlerMap.put(commandClass, commandHandler);
			LOGGER.debug("命令处理器 '" + commandHandler.getClass() + "' 绑定命令 '"
					+ commandClass + "'");
		}
	}

	/**
	 * 反注册命令。
	 * 
	 * @param commandHandler
	 *            命令处理器
	 */
	public synchronized static void unregister(
			CommandHandler<? extends Command<?>, ?> commandHandler) {
		AssertUtils.notNull(commandHandler);

		Class<? extends Command<?>> commandClass = commandHandler
				.getCommandClass();
		handlerMap.remove(commandClass);
		LOGGER.debug("命令 '" + commandClass + "' 取消绑定");
	}

	/**
	 * 反注册命令。
	 * 
	 * @param command
	 *            命令
	 */
	public synchronized static void unregister(
			Class<? extends Command<?>> commandClass) {
		AssertUtils.notNull(commandClass);

		handlerMap.remove(commandClass);
		LOGGER.debug("命令 '" + commandClass + "' 取消绑定");
	}

	/**
	 * 执行命令。
	 * 
	 * @param command
	 *            命令
	 * @return 命令执行结果
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static <T> T execute(Command<T> command) {
		AssertUtils.notNull(command);

		Class<? extends Command> commandClass = command.getClass();
		CommandHandler<? extends Command<?>, ?> handler = handlerMap
				.get(commandClass);
		if (handler == null) {
			throw new CommandHandlerNotFoundException(commandClass);
		}
		synchronized (handler) {
			try {
				Method execute = handler.getClass().getMethod("execute",
						commandClass);
				return (T) execute.invoke(handler, command);
			} catch (Exception ex) {
				ReflectionUtils.handleReflectionException(ex);
			}
		}
		throw new IllegalStateException("Should never get here");
	}
}